use super::{
    err, err_value, json, throw_err, Bytes, ConTcp, Connect, ECode, Resp, Seed, VBase, Value, VecV,
};

pub fn get_connect(id: &str, client: &Connect) -> Result<ConTcp, Value> {
    match client.get(id) {
        Some(v) => Ok(v.clone()),
        None => {
            throw_err!(ECode::Connect, "Connect PLC error");
        }
    }
}

pub fn write_bool(c: i64, val: &VecV) -> Result<Vec<bool>, Value> {
    let mut iter = val.iter();

    if c > 0 {
        let mut ret = Vec::new();

        for it in iter {
            let v = it.ckbool()?;
            ret.push(v);
        }

        ret.truncate(c as usize);

        return Ok(ret);
    }

    if let Some(it) = iter.next() {
        let v = it.ckbool()?;
        return Ok(vec![v]);
    }

    err!(ECode::EmptyData, "no data")
}

pub fn write_val(c: i64, val: &VecV) -> Result<Vec<i64>, Value> {
    let mut iter = val.iter();

    if c > 0 {
        let mut ret = Vec::new();

        for it in iter {
            let v = it.cki64()?;
            ret.push(v);
        }

        ret.truncate(c as usize);

        return Ok(ret);
    }

    if let Some(it) = iter.next() {
        let v = it.cki64()?;
        return Ok(vec![v]);
    }

    err!(ECode::EmptyData, "no data")
}

pub fn write_str(c: i64, val: &VecV) -> Result<Vec<Bytes>, Value> {
    let mut iter = val.iter();

    if c > 0 {
        let mut ret = Vec::new();

        for it in iter {
            let it = it.ckstr()?.to_string();
            let v = Bytes::from(it);
            ret.push(v);
        }

        ret.truncate(c as usize);

        return Ok(ret);
    }

    if let Some(it) = iter.next() {
        let it = it.ckstr()?.to_string();
        let v = Bytes::from(it);
        return Ok(vec![v]);
    }

    err!(ECode::EmptyData, "no data")
}

pub fn write_float(c: i64, val: &VecV) -> Result<Vec<f64>, Value> {
    let mut iter = val.iter();

    if c > 0 {
        let mut ret = Vec::new();

        for it in iter {
            let v = it.ckf64()?;
            ret.push(v);
        }

        ret.truncate(c as usize);

        return Ok(ret);
    }

    if let Some(it) = iter.next() {
        let v = it.ckf64()?;
        return Ok(vec![v]);
    }

    err!(ECode::EmptyData, "no data")
}

fn eq_int(val: i64, org: Option<i64>) -> Value {
    match org {
        Some(v) => {
            let t = if v == val { true } else { false };
            json!(t)
        }
        None => json!(val),
    }
}

pub async fn get_val(t: &str, eq: Option<i64>, seed: &Seed) -> Resp {
    let mut data = seed.lock().await;

    *data += 1;

    if *data >= 100 {
        *data = 0;
    }

    let index = *data;

    let v = match t {
        "bool" => {
            let val = vec![true, false, true, false, true];
            json!(val[(index % 5) as usize])
        }
        "arraybool" => {
            let val = vec![true, false, true, false, true];
            let t = val[(index % 5) as usize];

            let mut tmp = Vec::new();

            for _i in 0..8 {
                tmp.push(t);
            }

            json!(tmp)
        }
        "char" => {
            let val = vec!['a', 'b', 'c', 'd', 'e', 'f'];
            json!(val[(index % 5) as usize])
        }
        "byte" => {
            json!(index)
        }
        "int16" => {
            let v = eq_int(index * 100, eq);
            json!(v)
        }
        "uint16" => {
            let v = eq_int(index * 100 + 1, eq);
            json!(v)
        }
        "int32" => {
            let v = eq_int(index * 1000, eq);
            json!(v)
        }
        "uint32" => {
            let v = eq_int(index * 1000 + 1, eq);
            json!(v)
        }
        "int64" => {
            let v = eq_int(index * 10000, eq);
            json!(v)
        }
        "uint64" => {
            let v = eq_int(index * 10000 + 1, eq);
            json!(v)
        }
        "float" => {
            let v = (index * 100) as f64 + 0.11;
            json!(v)
        }
        "double" => {
            let v = (index * 100) as f64 + 0.22;
            json!(v)
        }
        "string" => {
            let v = format!("{}", index * 10);
            json!(v)
        }
        _ => throw_err!(ECode::Para, "read plc type error"),
    };

    Ok(v)
}
